package com.yeskery.nut.bean.scheduling;

import com.yeskery.nut.annotation.scheduling.Scheduled;
import com.yeskery.nut.application.ServerEventContext;
import com.yeskery.nut.bean.ApplicationContext;
import com.yeskery.nut.bean.BeanPostProcessor;
import com.yeskery.nut.bean.FactoryBeanRegister;
import com.yeskery.nut.plugin.ServerEventPlugin;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;

/**
 * 定时调度注解bean后置处理器
 * @author sprout
 * @version 1.0
 * 2024-06-04 23:00
 */
public class ScheduledBeanPostProcessor implements BeanPostProcessor, ServerEventPlugin {

    /** 定时调度执行器 */
    private final ScheduledExecutor scheduledExecutor;

    /**
     * 构建定时调度注解bean后置处理器
     * @param scheduledExecutor 定时调度执行器
     */
    public ScheduledBeanPostProcessor(ScheduledExecutor scheduledExecutor) {
        this.scheduledExecutor = scheduledExecutor;
    }

    @Override
    public void process(Object bean, Class<?> beanClass, ApplicationContext applicationContext, FactoryBeanRegister factoryBeanRegister) {
        for (Method method : beanClass.getMethods()) {
            if (isValidScheduledMethod(method)) {
                ScheduledMetadata scheduledMetadata = new ScheduledMetadata();
                scheduledMetadata.setBean(bean);
                scheduledMetadata.setMethod(method);
                scheduledMetadata.setScheduled(method.getAnnotation(Scheduled.class));
                scheduledExecutor.addScheduledMetadata(scheduledMetadata);
            }
        }
    }

    @Override
    public int getOrder() {
        return 0;
    }

    @Override
    public void afterStart(ServerEventContext serverEventContext) {
        scheduledExecutor.start();
    }

    /**
     * 是否是有效的方法
     * @param method 方法对象
     * @return 是否是有效的方法
     */
    private boolean isValidScheduledMethod(Method method) {
        int modifiers = method.getModifiers();
        return !Modifier.isStatic(modifiers) && !Modifier.isAbstract(modifiers) && Modifier.isPublic(modifiers)
                && method.isAnnotationPresent(Scheduled.class) && method.getParameterCount() == 0;
    }
}
